using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Projekt.Models;
using Projekt.Models.Primitives;
using Projekt.Cameras;
using Projekt.Actors;

namespace Projekt
{
    public class Engine : Microsoft.Xna.Framework.Game
    {
        #region Variables
        GraphicsDeviceManager graphics;

        public bool gameStarted = false;

        float frameRate; // FPS counter

        public List<CustomModel> models = new List<CustomModel>();
        public BaseCamera camera;
        public ChaseCamera chaseCamera;
        public FreeCamera freeCamera;
        public ArcBallCamera arcBallCamera;
        public TargetCamera targetCamera;

        public MouseState lastMouseState, savedMouseState, mouseState;
        
        SpriteBatch spriteBatch;
        Texture2D selectionBoxTex;
        #endregion

        #region Constructor & Initialization
        public Engine()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;

            Content.RootDirectory = "Content";

            IsMouseVisible = true;

            this.Exiting += new EventHandler<EventArgs>(Engine_Exiting);
        }

        void Engine_Exiting(object sender, EventArgs e)
        {
            gameStarted = false;
        }

        protected override void Initialize()
        {
            base.Initialize();
        } 
        #endregion

        #region Load/Unload Content

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            //selectionBoxTex = Content.Load<Texture2D>(@"Textures\SelectionBox");

            models.Add(new CustomModel("sphere", Vector3.Zero, Vector3.Zero, new Vector3(1f), GraphicsDevice, this));
            models.Add(new CustomModel("ground", new Vector3(0, -300, 0), Vector3.Zero, new Vector3(1000), GraphicsDevice, this));

            Player.Initialize(models[0], this);

            arcBallCamera = new ArcBallCamera(Player.Model, 0, 45, 45, 45, 10000, 10, 100000, GraphicsDevice);
            chaseCamera = new ChaseCamera(new Vector3(0, 20000, 0), new Vector3(0, 200, 0), new Vector3(0, 0, 0), GraphicsDevice);
            targetCamera = new TargetCamera(new Vector3(0, 20000, 0), Player.Model, GraphicsDevice);
            freeCamera = new FreeCamera(new Vector3(0, 20000, 0), MathHelper.ToRadians(0), MathHelper.ToRadians(-90), GraphicsDevice);
            camera = arcBallCamera;

            lastMouseState = Mouse.GetState();
        }

        protected override void UnloadContent()
        {
        } 
        #endregion

        #region Updates

        protected override void Update(GameTime gameTime)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                this.Exit();

            this.Window.Title = "Strategia [FPS: " + (int)frameRate + "]";

            mouseState = Mouse.GetState();

            Player.Update(gameTime);
            updateCamera(gameTime);
            selection();
            
            lastMouseState = mouseState;

            base.Update(gameTime);
        }

        private void updateCamera(GameTime gameTime)
        {
            if (camera.GetType() == typeof(ChaseCamera))
            {
                // Move the camera to the new model's position and orientation
                ((ChaseCamera)camera).Move(models[0].Position, models[0].Rotation);
            }
            else if (camera.GetType() == typeof(FreeCamera))
            {
                if (mouseState.RightButton == ButtonState.Pressed && lastMouseState.RightButton == ButtonState.Released)
                {
                    this.IsMouseVisible = false;
                    savedMouseState = lastMouseState;
                    Mouse.SetPosition(GraphicsDevice.PresentationParameters.BackBufferWidth / 2, GraphicsDevice.PresentationParameters.BackBufferHeight / 2);
                }
                else if (mouseState.RightButton == ButtonState.Pressed && lastMouseState.RightButton == ButtonState.Pressed)
                {
                    ((FreeCamera)camera).Fly(gameTime);
                }
                else if (mouseState.RightButton == ButtonState.Released && lastMouseState.RightButton == ButtonState.Pressed)
                {
                    Mouse.SetPosition(savedMouseState.X, savedMouseState.Y);
                }
                else
                    this.IsMouseVisible = true;
            }
            else if (camera.GetType() == typeof(ArcBallCamera))
            {
                if (mouseState.RightButton == ButtonState.Pressed && lastMouseState.RightButton == ButtonState.Released)
                {
                    this.IsMouseVisible = false;
                    savedMouseState = lastMouseState;
                    Mouse.SetPosition(GraphicsDevice.PresentationParameters.BackBufferWidth / 2, GraphicsDevice.PresentationParameters.BackBufferHeight / 2);
                }
                else if (mouseState.RightButton == ButtonState.Pressed && lastMouseState.RightButton == ButtonState.Pressed)
                {
                    ((ArcBallCamera)camera).Fly(gameTime);
                }
                else if (mouseState.RightButton == ButtonState.Released && lastMouseState.RightButton == ButtonState.Pressed)
                {
                    Mouse.SetPosition(savedMouseState.X, savedMouseState.Y);
                }
                else
                    this.IsMouseVisible = true;
            }
            else if (camera.GetType() == typeof(TargetCamera))
            {
                ((TargetCamera)camera).Update();
            }

            camera.UpdateMouseRay(new Vector2(mouseState.X, mouseState.Y), GraphicsDevice.Viewport);
            camera.Update();
        }


        List<CustomModel> selectedItems = new List<CustomModel>();
        void selection()
        {
            if (IsMouseVisible)
            {
                if (lastMouseState.LeftButton == ButtonState.Pressed && mouseState.LeftButton == ButtonState.Released)
                {
                    foreach (CustomModel cModel in models)
                    {
                        cModel.Components[1].Visible = false;
                    }

                    selectedItems.Clear();

                    float minDist = float.MaxValue;
                    float? dist;
                    for (int i = 0; i < models.Count(); i++)
                    {
                        dist = camera.MouseRay.Intersects(models[i].BoundingBox);
                        if (dist != null && dist < minDist)
                        {
                            minDist = (float)dist;
                            selectedItems.Add(models[i]);
                        }
                    }

                    if(selectedItems.Count()>0) selectedItems.Last().Components[1].Visible = true;
                }
            }
        }
        #endregion

        #region Draw

        protected override void Draw(GameTime gameTime)
        {
            if (!gameStarted) gameStarted = true;

            GraphicsDevice.Clear(Color.AntiqueWhite);
            
            // FPS count
            frameRate = 1 / (float)gameTime.ElapsedGameTime.TotalSeconds;

            base.Draw(gameTime);
        } 
        #endregion
    }
}
